/*
 * Copyright (c) 2003-2010, Live Media Pty. Ltd.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted
 * provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice, this list of
 *     conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice, this list of
 *     conditions and the following disclaimer in the documentation and/or other materials
 *     provided with the distribution.
 *  3. Neither the name of Live Media nor the names of its contributors may be used to endorse
 *     or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.argot.contiki;

import java.io.FileNotFoundException;
import java.io.IOException;

import com.argot.TypeException;
import com.argot.TypeLibrary;
import com.argot.TypeLibraryLoader;
import com.argot.common.CommonLoader;
import com.argot.dictionary.DictionaryLoader;
import com.argot.meta.MetaExtensionLoader;
import com.argot.meta.MetaLoader;
import com.argot.network.NetArgotLoader;
import com.argot.remote.MetaLocation;
import com.argot.remote.MetaObject;
import com.argot.remote.RemoteLoader;

import com.colony.ColonyEnvironment;
import com.colony.ColonyException;
import com.colony.concurrent.SystemThreadPool;
import com.colony.container.simple.SimpleContainer;
import com.colony.container.simple.SimpleLoader;
import com.colony.container.simple.SimpleLocation;
import com.colony.remote.RemoteException;
import com.colony.remote.rpc.RpcClient;
import com.colony.remote.rpc.RpcLoader;
import com.colony.transport.udp.UdpClient;

public class ArgotUdpClient
{
	private static final String LINK1 = "link";
	
	private TypeLibrary _library;
	private ColonyEnvironment _client;

	public ArgotUdpClient( String server, int serverPort) 
	throws Exception
	{
		_library = configTypeLibrary();
		_client = configColonyClient( server, serverPort );
	}
	
	/*
	 * Loads and configures the Argot type library. 
	 * Each of the libraryLoader classes load a corresponding dictionary and
	 * binds java classes to each type.  This should be a singleton object
	 * across the application.
	 */
	private TypeLibrary configTypeLibrary()
	throws TypeException, FileNotFoundException, IOException
	{
		TypeLibraryLoader libraryLoaders[] = {
				new MetaLoader(),
				new DictionaryLoader(),
				new MetaExtensionLoader(),
				new CommonLoader(),
				new RemoteLoader(),
				new NetArgotLoader(),
				new RpcLoader(),
				new SimpleLoader(),
				new TestLoader()
			};
		
		TypeLibrary library = new TypeLibrary( libraryLoaders );
		return library;
	}	
		
	/*
	 *  Configures the Colony client environment.
	 *  Colony uses the concept of containers on each peer.  The client in this case
	 *  uses a SimpleContainer (which is not used in this case).  The client is
	 *  then configured with an RpcClient/UdpClient combination.  The RpcClient combines
	 *  a RPC protocol with the Argot type agreement protocol.  The UdpClient transports
	 *  the requests and receives the responses over UDP.  Each server is configured using
	 *  a link or server name.
	 */
	private ColonyEnvironment configColonyClient( String server, int serverPort ) 
	throws FileNotFoundException, TypeException, IOException, ColonyException, RemoteException
	{	
		
		SimpleContainer clientContainer = new SimpleContainer( _library );
		ColonyEnvironment client = new ColonyEnvironment(clientContainer, _library );
		
		UdpClient udpClient = new UdpClient(SystemThreadPool.getThreadPool(),server,serverPort);
		RpcClient rpcClient = new RpcClient(udpClient);
		rpcClient.disableMetaDictionaryCheck();
		client.addClient(LINK1, rpcClient);		
		
		return client;
	}
	
	
	/*
	 *  Returns the interface specified on the server.
	 *  The location of the remote object is specified using a SimpleLocation which provides an
	 *  index into a container on the remote device.  The object reference combines the interface
	 *  type identifier as specified in the type library with the location.
	 *
	 */
	public ITest getRemoteTestInterface() throws Exception
	{
		// Create the object reference
		int testInterfaceId = _client.getTypeLibrary().getTypeId(ITest.TYPENAME,"1.3");
		MetaLocation testLocation = new SimpleLocation(2, LINK1);
		MetaObject objectReference = new MetaObject( testLocation, testInterfaceId );

		// get the interface from the client.
		return (ITest) _client.getFront( objectReference );
	}
	

	public static void main(String[] args)
	{
		int serverPort = 50000;
		
		if (args.length == 0 )
		{
			System.err.println("Usage: ArgotUdpClient <server ip address>");
			System.exit(1);
		}
		
		try
		{
			ArgotUdpClient client = new ArgotUdpClient(args[0], serverPort);
			ITest test = client.getRemoteTestInterface();
			
			int i = test.doSomething(10);
			System.out.println("doSomething returned: " + i );
		} 
		catch (Exception e)
		{
			e.printStackTrace();
		} 
	} 
}
